﻿using Anni.Weixin.Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web.Security;

namespace Anni.Weixin.API.weixin {
	public class WeiXinJSSDK {
		private string appId;           //应用ID/开发者ID
		private string appSecret;       //应用密钥
		public WeiXinJSSDK() {
		}
		public WeiXinJSSDK(string appId, string appSecret) {
			this.appId = appId;
			this.appSecret = appSecret;
		}
		/// <summary>
		/// 生成签名的时间戳
		/// </summary>
		/// <returns>string</returns>
		public string GenerateTimeStamp() {
			var epoch = (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
			return Convert.ToInt64(epoch).ToString();
		}
		/// <summary>
		/// 生成签名的随机串
		/// </summary>
		/// <returns>string</returns>
		public string GenerateNonceStr() {
			return System.Guid.NewGuid().ToString().Replace("-", "");
		}
		/// <summary>
		/// 生成JS-SDK权限验证的签名
		/// </summary>
		/// <returns>string</returns>
		public string GenerateSignature(long timestamp, string nonceStr, string url) {
			try {
				string access_token = string.Empty; //access_token是公众号的全局唯一票据，有效期7200秒，这里我采用数据库来保存
				string jsapi_ticket = string.Empty; //jsapi_ticket的有效期为7200秒,通过access_token来获取.同样保存到数据库中
				//获取jsapi_ticket  
				jsapi_ticket = GetJsApiTicket();
				var strSHA1 = string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}", jsapi_ticket, nonceStr, timestamp, url);
				// 对strSHA1进行sha1签名，得到signature
				var signature = FormsAuthentication.HashPasswordForStoringInConfigFile(strSHA1, "SHA1");
				return signature;
			}
			catch (Exception) {

				throw;
			}
		}
		/// <summary>
		/// 获取jsapi_ticket 有效期7200秒, 超时则更新  
		/// </summary>
		/// <returns></returns>
		private string GetJsApiTicket() {
			Anni.Weixin.BLL.jsapi_ticket ticketBll = new Anni.Weixin.BLL.jsapi_ticket();
			string ticket = string.Empty;
			//从数据库读取
			Anni.Weixin.Model.jsapi_ticket ticketModel = ticketBll.GetModel(1);
			if (ticketModel != null && ticketModel.id > 0) {
				int expire_time = ticketModel.uptime;
				ticket = ticketModel.jsapiticket;
				if (expire_time < ConvertDateTimeInt(DateTime.Now) || string.IsNullOrEmpty(ticketModel.jsapiticket)) {
					string accessToken = GetAccessToken();//获取系统的全局token 
					string url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=" + accessToken + "";
					Jssdk sdk = JsonConvert.DeserializeObject<Jssdk>(httpGet(url));
					if (sdk != null && sdk.ticket != "") {
						ticket = sdk.ticket;
						expire_time = ConvertDateTimeInt(DateTime.Now) + 7000;
						//更新数据库jsapiticket
						ticketModel.jsapiticket = ticket;
						ticketModel.uptime = expire_time;
						ticketBll.Update(ticketModel);
					}
				}
			}
			else {
				string accessToken = GetAccessToken();//获取系统的全局token 
				string url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=" + accessToken + "";
				Jssdk sdk = JsonConvert.DeserializeObject<Jssdk>(httpGet(url));
				if (sdk != null && sdk.ticket != "") {
					//添加jsapiticket
					ticketModel = new jsapi_ticket();
					ticketModel.jsapiticket = sdk.ticket;
					ticketModel.uptime = ConvertDateTimeInt(DateTime.Now) + 7000;
					ticketBll.Add(ticketModel);
				}
			}
			return ticket;
		}
		/// <summary>
		///获取accesstoken 有效期7200秒, 超时则更新
		/// </summary>
		/// <returns></returns>
		private string GetAccessToken() {
			string access_token = "";
			Anni.Weixin.BLL.access_token accessBll = new Anni.Weixin.BLL.access_token();
			//从数据库读取
			Anni.Weixin.Model.access_token accessModel = accessBll.GetModel(1);
			if (accessModel != null && accessModel.id > 0) {
				int expire_time = Convert.ToInt32(accessModel.uptime); ;
				access_token = accessModel.accesstoken;
				if (expire_time < ConvertDateTimeInt(DateTime.Now) || string.IsNullOrEmpty(accessModel.accesstoken)) {
					string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret + "";
					AccToken iden = Desrialize<AccToken>(new AccToken(), httpGet(url));
					if (iden != null && iden.access_token != "") {
						access_token = iden.access_token;
						accessModel.accesstoken = access_token;
						accessModel.uptime = ConvertDateTimeInt(DateTime.Now) + 7000;
						accessBll.Update(accessModel);
					}
				}
			}
			else {
				string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret + "";
				AccToken iden = Desrialize<AccToken>(new AccToken(), httpGet(url));
				if (iden != null && iden.access_token != "") {
					accessModel = new Model.access_token();
					accessModel.accesstoken = iden.access_token;
					accessModel.uptime = ConvertDateTimeInt(DateTime.Now) + 7000;
					accessBll.Add(accessModel);
				}
			}
			return access_token;
		}
		/// <summary>  
		/// 序列化 对象到字符串  
		/// </summary>  
		/// <param name="obj">泛型对象</param>  
		/// <returns>序列化后的字符串</returns>  
		public static string Serialize<T>(T obj) {
			try {
				var serializer = new DataContractJsonSerializer(typeof(T));
				var stream = new MemoryStream();
				serializer.WriteObject(stream, obj);


				byte[] dataBytes = new byte[stream.Length];


				stream.Position = 0;


				stream.Read(dataBytes, 0, (int)stream.Length);


				string dataString = Encoding.UTF8.GetString(dataBytes);
				return dataString;
			}
			catch (Exception ex) {
				return null;
				throw new Exception("序列化失败,原因:" + ex.Message);
			}
		}

		/// <summary>  
		/// 反序列化 字符串到对象  
		/// </summary>  
		/// <param name="obj">泛型对象</param>  
		/// <param name="str">要转换为对象的字符串</param>  
		/// <returns>反序列化出来的对象</returns>  
		public static T Desrialize<T>(T obj, string str) {
			try {
				var mStream = new MemoryStream(Encoding.Default.GetBytes(str));
				var serializer = new DataContractJsonSerializer(typeof(T));
				T readT = (T)serializer.ReadObject(mStream);


				return readT;
			}
			catch (Exception ex) {
				return default(T);
				throw new Exception("反序列化失败,原因:" + ex.Message);
			}

		}
		/// <summary>  
		/// 将c# DateTime时间格式转换为Unix时间戳格式  
		/// </summary>  
		/// <param name="time">时间</param>  
		/// <returns>double</returns>  
		public int ConvertDateTimeInt(System.DateTime time) {
			int intResult = 0;
			System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
			intResult = Convert.ToInt32((time - startTime).TotalSeconds);
			return intResult;
		}
		/// <summary>
		///发起一个http请球，返回值 
		/// </summary>
		/// <param name="url"></param>
		/// <returns></returns>
		private string httpGet(string url) {
			try {
				WebClient MyWebClient = new WebClient();
				MyWebClient.Credentials = CredentialCache.DefaultCredentials;//获取或设置用于向Internet资源的请求进行身份验证的网络凭据  
				Byte[] pageData = MyWebClient.DownloadData(url); //从指定网站下载数据  
				string pageHtml = System.Text.Encoding.Default.GetString(pageData);  //如果获取网站页面采用的是GB2312，则使用这句              

				return pageHtml;
			}
			catch (WebException webEx) {
				Console.WriteLine(webEx.Message.ToString());
				return null;
			}
		}
	}
}
